#! /usr/bin/env python
# -*- coding: latin-1 -*-
## @package edi
#  Documentation for edi module. All Easydoneit CLI commands are defined in this module.
#
# Copyright (C) 2014 Spartatek AB
#
# contact@spartatek.se
# http://spartatek.se
#
# EASYDONEIT CLI is free software: you can redistribute it and/or modify
# it under the terms of the GNU Genereric Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# EASYDONIT CLI is distributed in the hope that it will be usesul,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Genereral Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# GNU licences http://www.gnu.org/licenses

import sys
import re
import shutil
import os
import ConfigParser
# 0 disable, 1 enable print
#:print_command_map=0
#:profiler=0

#:profiler
#:end

from edi_core import *
# Import to access data_location in edi_core
import edi_core

## functions to print results from list_tree/list_group
#  @ingroup EDI_CLI
def empty_line(tid,s):
	return ''

## functions to print results from list_tree/list_group
#  @ingroup EDI_CLI
def print_list(task_array):
	Functions = {'head group': generate_group_string_with_tid,'element': generate_task_string_with_tid}
	for t in task_array:
		print Functions.get(t['head'],empty_line)(t['tid'], '%3d - %s %s'%(t['position'],t['group'],t['title']))

#--------------------------------------------
# COMMAND LINE INTERFACE

## Default Function.
#  @ingroup EDI_CLI
def Nothing():
        print 'Command not available'

## add command name to COMMANDS, help to HELP_STRING and corresponding python functions to FUNCTIONS below
COMMANDS     = ['help','version','cr','lsid','add','cat','mkdir','show','rm','vi','order','set','reset','search','mv','cp','ln','path','tree','ls','stfi','data','html','select','default','cpb','mvb','fc','bc','createDatabase','topbot','in','re','st','zip','autolink','cv','user','email','stats','many','demo','list','merge','media','at']

## ls help for both edi lsid and edi ls
LS_HELP ='''edi lsid [-R|-G|-s|-L|-La|-Lx|-t] [group|task] [position]
	list tasks in a group. Outside tree folder, without parameter list all tasks and groups,
	with parameter list group or task title (selected with task id or group id and position),
	with -R list group recursively, with position print task title.
	In tree folder, without parameter list group,
	with -G and when cwd is in tree, list group path with ids and titles (group1/group2...),
	with task id parameter print tree path and title,
	-s for sorted list by status,
	-L list tasks in any group from groups in edi list (or),
	-La list tasks in all groups in edi list (and),
	-Lx list tasks in all groups in edi list exclusively (strictly and)
	-t sort by date from oldest to newest task'''

## help command displays these strings
HELP_STRINGS = ['''edi help [command]
	print cli commands and data location, command parameter is optional''',
                'print current version',
                '''edi cr [group]
	create task and open text editor, calls without parameters create task in root group,
	when in tree and without parameter, create task in current group,
	when group parameter is provided create task in group''',
		LS_HELP,
		'''edi add [-F|-t] [group] text_filename|text
	add task from file. Without parameter add task in root group,
	when in tree and without parameter, add task in current group,
	add_task option (-F) text_filename adds task with filename in fist line of description in root group,
	add_task option (-F) group text_filename adds task with filename in first line of description in group,
	add_task group text_filename adds task in group
	edi add -t [group] 'text' creates a task with description text''',
		'''edi cat group|task|position [position]
	print description. With position parameter print description for task at given position,
	when in tree and without group parameter, print description at given position in current group''',
		'''edi mkdir task|position
	convert task to group
	when in tree, convert task at given position''',
		'''edi show task|position
	print group title for task''',
		'''edi rm task|group|position [task]
	delete task or group
	with group and task parameters, delete task and keep linked tasks
	edi rm root deletes all tasks in default database''',
		'''edi vi task|group|position [position]
	edit description,
	in tree, edit task or group at given position in current group''',
		'''edi order [group] at_position to_position
	change order in group. Without group parameter change order in root group,
	in tree change order in current group''',
		'''edi set task|group|position int_status
	set status to int parameter,
	int_status values are:
%s'''%'\n'.join(['	%d: %s'%(i,j.strip()) for i,j in enumerate(TASK_STATUS)]),
		'''edi reset group
	set tasks in group to active. Without parameter set tasks in root group''',
		'''edi search string
	search string in tasks folder,
	in tree, searches in current group''',
		'''edi mv group task|group group
	edi mv position group
	move task or group,
	move task or group from group parameter 1 to group parameter 3''',
		'''edi cp [-E] task|group|position group|path
	copy task to a group,
	option -E copy description to path, first line in description is filename''',
		'''edi ln task|position group
	add a reference in group''',
		'''edi path task|group|position
	print task filesystem path''',
		'''edi tree
	print tree path''',
		LS_HELP.replace('edi lsid ','edi ls ').replace('list tasks in a group','ls groups and tasks with positions only'),
		'''edi stfi status_filter state
	enable/disable (set) status filter,
	without parameters, print current filters,

	status_filter values are:
%s

	state values are:
%s'''%('\n'.join(['	%s'%i.strip() for i in TASK_STATUS]), '\n'.join(['	%s'%i for i in STATUS_FILTER_STATES])),
		'''edi data [-d] [database_name] [path]
	set path for database and create database when it doesnt exist,
	without option, print current data path
	Option -d delete a database''',
		'''edi html [-R|-G|-s|-L|-La|-Lx|-t] group|task [position]
	generate html for tasks, same options as ls''',
		'''edi select [database_name_1,database_name2...]
	set selected databases
	without option, print selected databases''',
		'''edi default [database_name]
	set default database for new tasks
	without option, print default database''',
		'''edi cpb task|group|position database group
	copy task or group to database/group''',
		'''edi mvb group task|group database group
	edi mvb position database group
	move task or group to database/group''',
		'''edi fc task|group|position [color]
	set/get forground color from task or group
	color is 4 decimal numbers seperated with commas
	0,0,0,255''',
		'''edi bc task|group|position [color]
	set/get background color from task or group
	color is 4 decimal numbers seperated with commas
	0,0,0,255''',
		'''edi createDatabase database_name path
	create database folders and set path
	this command creates the path when it doesnt exist''',
		'''edi topbot [top|bottom]
	select add new tasks in bottom of group or on top of group
	Default is bottom
	without parameter, print status''',
		'''edi in [-A] group|position
	print group tasks in md format
	when in tree, print group at given position
	option -A create an agenda after title for slideshows''',
		'''edi re [-A] group|position
	print group tasks in reStructuredText format
	when in tree, print group at given position
	option -A create an agenda after title for slideshows''',
		'''edi st
	shows trees for selected databases, print all trees: group tids and titles''',
		'''edi zip database_name [path]
	creates an archive of the database in database_name.tar.bz2 in path or current folder''',
		'''edi autolink [group1,group2...]
	set configuration for linking new tasks to autolink groups
	without option, print autolink group list''',
		'''edi cv group|pos
	convert empty group to task''',
		'''edi user [First name Last name]
	set user name
	without parameter, display username''',
		'''edi email [user email]
	set user email
	without parameter, display user email''',
		'''edi stats [group]
	show statistics
	without parameter, show statistics in selected databases or current group in tree''',
		'''edi many [-1|-g] [group] text_file
	add many tasks from a file, tasks are seperated with '---' lines
	with -1, add one task per line from a file,
	with -g, create a group per line from file, one space for deeper levels''',
		'''edi demo
	display commands to show how to use Easydoneit CLI''',
		'''edi list group1,group2...
	set a list of groups for edi ls -L,-La and -Lx options
	the groups have to be in the same database
	without parameter, list groups''',
		'''edi merge [path|database_name] database_name_2
	copy tasks from database_name to database_name_2 with no changes
	WARNING - the source database is merged correctly several times when the tree remains the same since the first merge.''',
		'''edi media [task|pos] [image file|sound file]
	copy media file to task. Only one media file per task is allowed, for more attachments use edi at
	without parameter, show media type''',
		'''edi at [task|pos] [filename|*]
	copy file to task as attachments.
	without parameter, show attachment files''']

HELP          = zip(COMMANDS,HELP_STRINGS)
HELP_DICT     = dict(HELP)

## print cli commands and data location
#
#  print format:<br>
#  command<br>
#  TAB help string
#  @ingroup EDI_CLI
def help():
	print 'Easydoneit help'
	print 'http://spartatek.se/easydoneit_cli'
	print
#:define edi_version
	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
	v = f.readline()
	f.close()
	print 'Version %s'%v
#:end
	print 'Selected data_location'
	print edi_core.data_location
	print
	if len(sys.argv) < 3:
		# print complete help
		for c,h in HELP:
			print c
			print '	%s\n'%h

	# print help for specified command
	if len(sys.argv) == 3:
		if not sys.argv[2] in HELP_DICT.keys():
			sys.exit('%s is invalid command.'%sys.argv[2])
		print sys.argv[2]
		print '	%s\n'%HELP_DICT[sys.argv[2]]


## print current version
#  @ingroup EDI_CLI
def version():
#:edi_version
	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
	v = f.readline()
	f.close()
	print 'Version %s'%v

## create task and open text editor, calls without parameters create task in root group, when group parameter is provided create task in group
#  @ingroup EDI_CLI
def create_task_cli():
	# Select group and database

#:define figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break
#:end

	# Initialize group in case len(sys.argv) != 2
	group = ''
	if len(sys.argv) == 2:
		# no parameter - just command
		# select current group when in tree
		if status == 'in tree':
			#get_current_group_in_tree
			if cwd.split('/')[-1] == 'tree':
				group = 'root'
			else:
				group = cwd.split('/')[-1]
			#end
		else:
			# default group
			group = 'root'

	if (len(sys.argv) == 2) and (group == 'root') and (not status):
		# set default database when group is root and cwd not in tree
#:define set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
#:end
	if len(sys.argv) >= 3:
		group = sys.argv[2]

	if (group != 'root') and ((not status) or (len(sys.argv) == 3)):
		# find group in selected databases and setup data_location when not in tree or group is parameter
#:define find_group_in_selected_databases_and_setup_data_location
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			groups = os.listdir(edi_core.data_location_groups)
			if group in groups:
				break
#:end
	# Verify parameter
	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)
	print create_task(group)

## list tasks in a group. Outside tree folder, without parameter list all tasks and groups, with parameter list group or task title, with -R list group recursively, with position print task title. In tree folder, without parameter list group, with -G list group path with ids and titles, with task id parameter print tree path and title
#  @ingroup EDI_CLI
def ls_generic():
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	# Decide what to execute
	if len(sys.argv) == 2:
		if status:
			exe = 'ls in tree'
		else:
			exe = 'ls root'
	else:
		if (sys.argv[2] == '-R') or (sys.argv[2] == '-G') or (sys.argv[2] == '-s') or (sys.argv[2] == '-t'):
			if len(sys.argv) == 4:
				# there is a task id parameter, use that instead of tree location
				tid    = sys.argv[3]
				status = ''
			else:
				tid = 'root'
		else:
			tid = sys.argv[2]

		if status:
			# in tree, set tid to cwd
			tid = cwd.split('/')[-1]

#:define find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
#:end
		if is_this_task_a_group(sys.argv[2]):
			if len(sys.argv) == 3:
				exe = 'ls group'
			else:
				exe = 'ls at position'
		elif sys.argv[2] == '-R':
			if (is_this_task_a_group(tid)) or (tid == 'tree'):
				exe = 'ls tree'
				# tid is tree when cwd is at root, change to root for ls -R.
				if tid == 'tree':
					tid = 'root'
			else:
				exe = 'ls task'
				# replace -R option with tid and run regular ls task
				sys.argv[2] = tid
		elif sys.argv[2] == '-s':
			exe = 'ls sort'
			# tid is tree when cwd is at root, change to root for ls -s.
			if tid == 'tree':
				tid = 'root'
		elif sys.argv[2] == '-t':
			exe = 'ls sort by date'
			# tid is tree when cwd is at root, change to root for ls -t.
			if tid == 'tree':
				tid = 'root'
		elif sys.argv[2] == '-L':
			exe = 'ls any selected groups'
		elif sys.argv[2] == '-La':
			exe = 'ls all in selected groups'
		elif sys.argv[2] == '-Lx':
			exe = 'ls all in selected groups exclusively'
		elif sys.argv[2] == '-G' and status:
			exe = 'ls groups in tree path'
		else:
			exe         = 'ls task'
			if sys.argv[2] == '-G':
				if len(sys.argv) < 4:
					exe = 'ls root'
				else:
					# replace -G option with tid and run regular ls task
					sys.argv[2] = sys.argv[3]

	if exe == 'ls in tree':
		if cwd.split('/')[-1] == 'tree':
			exe         = 'ls group root'
		else:
			print_list(list_group(cwd.split('/')[-1]))
	if exe == 'ls root':
		# print root in all selected databases
#:define loop_on_selected_databases
		z = zip(edi_core.selected, edi_core.selected_path)
		for d,path in z:
			print '%s - %s' % (d,path)
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location)
#:end
			print_list(list_tree('root'))
	if exe == 'ls group root':
		print_list(list_group('root'))
	if exe == 'ls group':
		group = sys.argv[2]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_group_in_selected_databases_and_setup_data_location
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			groups = os.listdir(edi_core.data_location_groups)
			if group in groups:
				break
		if group == 'root':
			z = zip(edi_core.selected, edi_core.selected_path)
			for d,path in z:
				print '%s - %s' % (d,path)
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location)
				print_list(list_group(group))
		else:
			print_list(list_group(group))
	if exe == 'ls at position':
		# Find task at given postion
		group    = sys.argv[2]
		try:
			position = int(sys.argv[3])
		except:
			sys.exit('%s is invalid position'%sys.argv[3])
#:define find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
#:end
		# End - Find task at given postion
		print generate_task_string_with_tid(tid,get_task_title(tid))
	if exe == 'ls tree':
		print_list(list_tree(tid))
	if exe == 'ls groups in tree path':
		# p is data_location folder/tree
		p = '/'.join(p_l)
		# if empty then command is run in tree root
		if cwd.split(p)[-1]:
			# print path of tids: tid/tid...
			print cwd.split(p)[-1][1:]
			group_titles_in_path = []
			for g in cwd.split(p)[-1][1:].split('/'):
				group_titles_in_path.append(get_task_title(g))
			# print title/title...
			print '/'.join(group_titles_in_path)
	if exe == 'ls task':
		if status:
			# print group path titles and task
			# in tree folder
			p = '/'.join(p_l)
			# if empty then command is run in tree root
			if cwd.split(p)[-1]:
				print cwd.split(p)[-1][1:]
				group_titles_in_path = []
				for g in cwd.split(p)[-1][1:].split('/'):
					group_titles_in_path.append(get_task_title(g))
				# print title/title...
				print '/'.join(group_titles_in_path)
			# Verify that task sys.argv[2] is in database
			tasks = os.listdir(edi_core.data_location_tasks)
			if not sys.argv[2] in tasks:
				sys.exit('%s not found.'%sys.argv[2])
			print generate_task_string_with_tid(sys.argv[2],get_task_title(sys.argv[2]))
		else:
			#find_task_in_selected_databases_and_setup_data_location
			tid_in_database = ''
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				tasks = os.listdir(edi_core.data_location_tasks)
				if sys.argv[2] in tasks:
					tid_in_database = 'yes'
					break
			if not tid_in_database:
				sys.exit('%s not found.'%sys.argv[2])
			print generate_task_string_with_tid(sys.argv[2],get_task_title(sys.argv[2]))

	if exe == 'ls sort':
		if not is_this_task_a_group(tid):
			sys.exit('%s is not a group.'%tid)
		task_attributes = list_group(tid)
		sorted_tasks    = sort_task_attributes(task_attributes)
		print_list(sorted_tasks)

	if exe == 'ls sort by date':
		if not is_this_task_a_group(tid):
			sys.exit('%s is not a group.'%tid)
		task_attributes = list_group(tid)
		sorted_tasks    = sort_task_attributes_by_date(task_attributes)
		print_list(sorted_tasks)

	if exe == 'ls any selected groups':
		if not edi_core.list_of_groups:
			sys.exit('List empty')

		tid = edi_core.list_of_groups[0]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break

		# check that all groups are available in the database
		status = 'search groups'
		for g in edi_core.list_of_groups:
			if not is_this_task_a_group(g):
				status = 'group not found, edi cannot list all groups'
		if status == 'group not found, edi cannot list all groups':
			sys.exit(status)

		# list tasks in all groups
		task_attributes = list_group(tid)
		empty_line      = task_attributes[-1]
		# remove empty lines between groups
		del task_attributes[-1]

		# add other groups to the list
		for tid in edi_core.list_of_groups[1:]:
			# remove head group, keep head group only for first group in the group list
			# remove empty lines between groups
			task_attributes += list_group(tid)[1:-1]

		# remove duplicated tasks
		tasks = []
		tasks.append(task_attributes[0])
		# array used to prevent duplicated tasks
		tids  = []
		for t in task_attributes[1:]:
			if not t['tid'] in tids:
				tasks.append(t)
				tids.append(t['tid'])

		tasks.append(empty_line)
		print_list(tasks)


	if exe == 'ls all in selected groups':
		if not edi_core.list_of_groups:
			sys.exit('List empty')

		tid = edi_core.list_of_groups[0]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break

		if len(edi_core.list_of_groups) == 1:
			if not is_this_task_a_group(tid):
				sys.exit('%s not found, edi cannot list all groups' % tid)
			# only one group, regular ls
			print_list(list_group(tid))
			sys.exit(0)

		# check that all groups are available in the database
		status = 'search groups'
		for g in edi_core.list_of_groups:
			if not is_this_task_a_group(g):
				status = 'group not found, edi cannot list all groups'
		if status == 'group not found, edi cannot list all groups':
			sys.exit(status)

		# list tasks in all groups
		task_attributes = list_group(tid)
		empty_line      = task_attributes[-1]
		# remove empty lines between groups
		del task_attributes[-1]

		# add other groups to the list
		for tid in edi_core.list_of_groups[1:]:
			# remove head group, keep head group only for first group in the group list
			# remove empty lines between groups
			task_attributes += list_group(tid)[1:-1]

		# keep tasks only in all listed groups
		tasks = []
		tasks.append(task_attributes[0])
		# array used to prevent duplicated tasks
		tids  = []
		for t in task_attributes[1:]:
			if is_linked(t['tid']):
				groups = os.listdir('%s/groups/' % generate_task_path(t['tid']))
				# check that the task in all listed group
				status = 'all in groups'
				for g in edi_core.list_of_groups:
					if not g in groups:
						status = 'missing group'
				if (status == 'all in groups') and (not t['tid'] in tids):
					tasks.append(t)
					tids.append(t['tid'])


		tasks.append(empty_line)
		print_list(tasks)

	if exe == 'ls all in selected groups exclusively':
		if not edi_core.list_of_groups:
			sys.exit('List empty')

		tid = edi_core.list_of_groups[0]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break

		# check that all groups are available in the database
		status = 'search groups'
		for g in edi_core.list_of_groups:
			if not is_this_task_a_group(g):
				status = 'group not found, edi cannot list all groups'
		if status == 'group not found, edi cannot list all groups':
			sys.exit(status)

		# list tasks in all groups
		task_attributes = list_group(tid)
		empty_line      = task_attributes[-1]
		# remove empty lines between groups
		del task_attributes[-1]

		# add other groups to the list
		for tid in edi_core.list_of_groups[1:]:
			# remove head group, keep head group only for first group in the group list
			# remove empty lines between groups
			task_attributes += list_group(tid)[1:-1]

		# keep tasks only in all listed groups
		tasks = []
		tasks.append(task_attributes[0])
		# array used to prevent duplicated tasks
		tids  = []
		for t in task_attributes[1:]:
			if is_linked(t['tid']):
				groups = os.listdir('%s/groups/' % generate_task_path(t['tid']))
				# check that the task in all listed group exclusively
				status = 'all groups in list_of_groups'
				for g in groups:
					if not g in edi_core.list_of_groups:
						status = 'a group is not in the list'
				if (status == 'all groups in list_of_groups') and (len(groups) == len(edi_core.list_of_groups)) and (not t['tid'] in tids):
					tasks.append(t)
					tids.append(t['tid'])


		tasks.append(empty_line)
		print_list(tasks)


## list with tids
#  @ingroup EDI_CLI
def lsid():
	# list tids and positions
	edi_core.list_option = 'tids'

	ls_generic()

# ls groups and tasks with positions
#  @ingroup EDI_CLI
def ls():
	# list positions only
	edi_core.list_option = 'positions'

	ls_generic()

## add task from file. Without parameter add task in root group. add_task option (-F) text_filename add task with filename in fist line of description in root group. add_task option (-F) group text_filename add task with filename in first line of description in group. add_task group text_filename add task in group
#  @ingroup EDI_CLI
def add_task_cli():
	if len(sys.argv) < 3:
		# not enough parameters, call create_task
		create_task_cli()
		return

#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	options                = ''
	group_parameter_status = 'group is a command line parameter'
	if len(sys.argv) < 4:
		# Parameters are: command filename
		# select current group when in tree
		if status == 'in tree':
			#get_current_group_in_tree
			if cwd.split('/')[-1] == 'tree':
				group = 'root'
			else:
				group = cwd.split('/')[-1]
			#end
		else:
			# default group
			group = 'root'
		group_parameter_status = 'edi selected group'

		text_file = sys.argv[2]
	else:
		if ((sys.argv[2] == '-F') or (sys.argv[2] == '-t')) and len(sys.argv) == 4:
			options   = sys.argv[2]
			text_file = sys.argv[3]
			# select current group when in tree
			if status == 'in tree':
				#get_current_group_in_tree
				if cwd.split('/')[-1] == 'tree':
					group = 'root'
				else:
					group = cwd.split('/')[-1]
				#end
			else:
				# default group
				group = 'root'
			group_parameter_status = 'edi selected group'
		if ((sys.argv[2] == '-F') or (sys.argv[2] == '-t')) and len(sys.argv) == 5:
			options   = sys.argv[2]
			group     = sys.argv[3]
			text_file = sys.argv[4]
		if ((sys.argv[2] != '-F') and (sys.argv[2] != '-t')):
			group     = sys.argv[2]
			text_file = sys.argv[3]
	if not options:
		exe = 'add'
	else:
		if options == '-F':
			# option -F stores text_file filename in first line of description
			exe = 'add task and filename'
		elif options == '-t':
			# option -F stores text_file filename in first line of description
			exe = 'add text from command line'

	if (group == 'root') and (not status):
		# set default database when group is root and cwd not in tree
#:set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	if (group != 'root') and ((not status) or (group_parameter_status == 'group is a command line parameter')):
#:find_group_in_selected_databases_and_setup_data_location
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			groups = os.listdir(edi_core.data_location_groups)
			if group in groups:
				break

	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)

	if exe == 'add':
		if not os.path.exists(text_file):
			sys.exit('%s not accessible.'%text_file)
		print add_task(group,text_file)
	if exe == 'add task and filename':
		if not os.path.exists(text_file):
			sys.exit('%s not accessible.'%text_file)
		print add_task_and_filename(group,text_file)
	if exe == 'add text from command line':
		print add_text(group,text_file)

## print description. With position parameter print description for task at given position
#  @ingroup EDI_CLI
def cat():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	tid = sys.argv[2]

	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:define find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break
#:end

	if status == 'in tree':
#:define get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:end

	if (len(sys.argv) == 3) and (not status):
		# group parameter and not in tree
		tid = sys.argv[2]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break

	if (len(sys.argv) == 3) and (status == 'in tree'):
		# Find task at given postion
#:define get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:end
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)

	if len(sys.argv) == 4:
		group    = sys.argv[2]
		try:
			position = int(sys.argv[3])
		except:
			sys.exit('%s is invalid position'%sys.argv[3])
		# find_task_in_selected_databases_and_setup_data_location needs tid, here tid = group
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		if not is_this_task_a_group(group):
			sys.exit('%s is not a group.'%group)
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)

	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not tid in tasks:
		sys.exit('%s not found.'%tid)
	print ''.join(display_task(tid))

## convert task to group
#  @ingroup EDI_CLI
def mkdir():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:define tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
#:end

	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	# Verify that task is not already a group
	if is_this_task_a_group(sys.argv[2]):
		sys.exit('%s is already a group.'%sys.argv[2])
	print '\n'.join(create_group(sys.argv[2]))

## print group title for task
#  @ingroup EDI_CLI
def show_group_for_task_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break

	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	print '\n'.join(show_group_for_task(sys.argv[2]))

## delete task or group, or delete task in specified group, keep linked tasks
#  @ingroup EDI_CLI
def rm():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	if len(sys.argv) == 3:
		if is_this_task_a_group(sys.argv[2]):
			delete_group(sys.argv[2])
		else:
			# Verify that task tid is in database
			tasks = os.listdir(edi_core.data_location_tasks)
			if not sys.argv[2] in tasks:
				sys.exit('%s not found.'%sys.argv[2])
			delete_task(sys.argv[2])
	if len(sys.argv) == 4:
		# Verify that task tid is not root
		if sys.argv[3] == 'root':
			sys.exit('root is invalid task')
		# Verify that task tid is in database
		tasks = os.listdir(edi_core.data_location_tasks)
		if not sys.argv[2] in tasks:
			sys.exit('%s not found.'%sys.argv[2])
		# Verify group exists
		if not is_this_task_a_group(sys.argv[2]):
			sys.exit('%s is not a group.'%sys.argv[2])
		if not sys.argv[3] in tasks:
			sys.exit('%s not found.'%sys.argv[3])
		# delete task in specified group
		delete_linked_task(sys.argv[2], sys.argv[3])

## edit description
#  @ingroup EDI_CLI
def vi():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	tid = sys.argv[2]

	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]

	if (len(sys.argv) == 3) and (not status):
		# group parameter and not in tree
		tid = sys.argv[2]
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
	if (len(sys.argv) == 3) and (status == 'in tree'):
		# Find task at given postion
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
	if len(sys.argv) == 4:
		group    = sys.argv[2]
		try:
			position = int(sys.argv[3])
		except:
			sys.exit('%s is invalid position'%sys.argv[3])
		# find_task_in_selected_databases_and_setup_data_location needs tid, here tid = group
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		# Verify group exists
		if not is_this_task_a_group(sys.argv[2]):
			sys.exit('%s is not a group.'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)

	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not tid in tasks:
		sys.exit('%s not found.'%tid)
	edit_task(tid)

## change order in group. Without group parameter change order in root group, in tree change order in current group
#  @ingroup EDI_CLI
def change_order():
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
	else:
		group = 'root'


	if len(sys.argv) < 5:
		if not status:
			sys.exit('Missing group parameter.')
		at    = sys.argv[2]
		to    = sys.argv[3]
	else:
		group = sys.argv[2]
		at    = sys.argv[3]
		to    = sys.argv[4]

		if group == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location)
		else:
			#find_group_in_selected_databases_and_setup_data_location
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location)
				groups = os.listdir(edi_core.data_location_groups)
				if group in groups:
					break

	# Verify group exists
	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)
	# Verify at and to are numbers
	try:
		test = int(at)
	except:
		sys.exit('%s is invalid position'%at)
	try:
		test = int(to)
	except:
		sys.exit('%s is invalid position'%to)

	if int(at) < 0:
		sys.exit('Position %s is invalid.'%at)
	if int(to) < 0:
		sys.exit('Position %s is invalid.'%to)
	print '\n'.join(change_task_order(group,int(at),int(to)))

## set status to int parameter
#  @ingroup EDI_CLI
def set():
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	# Verify int_status parameter
	try:
		test = int(sys.argv[3])
	except:
		sys.exit('int_status %s is invalid.'%sys.argv[3])
	if test >= len(edi_core.TASK_STATUS):
		sys.exit('int_status %s is too large.'%sys.argv[3])
	if test < 0:
		sys.exit('int_status %s is invalid.'%sys.argv[3])
	set_status(sys.argv[2],int(sys.argv[3]))

## set tasks to active. Without parameter set tasks in root group
#  @ingroup EDI_CLI
def reset():
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]

	if (len(sys.argv) == 2) and (status != 'in tree'):
#:set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
		group = 'root'
	if (len(sys.argv) > 2) and (sys.argv[2] == 'root') and (not status):
		# set default database when group is root and cwd not in tree
#:set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
		group = 'root'
	# when group is root and in tree, dont change data_location
	if (len(sys.argv) > 2) and (sys.argv[2] != 'root'):
		group = sys.argv[2]
#:find_group_in_selected_databases_and_setup_data_location
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			groups = os.listdir(edi_core.data_location_groups)
			if group in groups:
				break

	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)
	reset_group_status(group)

## search string in tasks folder
#  @ingroup EDI_CLI
def search():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
		print ''.join(search_string_in_tree(group,sys.argv[2]))
	else:
#:loop_on_selected_databases
		z = zip(edi_core.selected, edi_core.selected_path)
		for d,path in z:
			print '%s - %s' % (d,path)
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location)
			print ''.join(search_string(sys.argv[2]))

## move task or group
#  @ingroup EDI_CLI
def move_task():
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')
	if len(sys.argv) == 5:
		tid = sys.argv[2]
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		# Verify parameters
		# Verify that task tid is not root
		if sys.argv[3] == 'root':
			sys.exit('root is invalid task')
		if not is_this_task_a_group(sys.argv[2]):
			sys.exit('%s is not a group.'%sys.argv[2])
		if not is_this_task_a_group(sys.argv[4]):
			sys.exit('%s is not a group.'%sys.argv[4])
		# Verify that task tid is in database
		tasks = os.listdir(edi_core.data_location_tasks)
		if not sys.argv[3] in tasks:
			sys.exit('%s not found.'%sys.argv[3])
		# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
		if is_this_task_a_group(sys.argv[3]):
			tree_path   = find_group_in_tree(sys.argv[4])
			parent_path = tree_path.split(sys.argv[4])[0]
			if sys.argv[3] in parent_path:
				print tree_path
				sys.exit('%s is a parent group for %s'%(sys.argv[3],sys.argv[4]))
		# Verify that group is not move on itself
		if sys.argv[3] == sys.argv[4]:
			sys.exit('Moving %s group on itself.'%sys.argv[3])
		# Verify that source group is not destination group
		if sys.argv[2] == sys.argv[4]:
			sys.exit('Source and destination groups are identical %s.'%sys.argv[2])
		tid = move_task_to_a_group(sys.argv[2],sys.argv[3],sys.argv[4])
		if len(tid) > edi_core.ID_LENGTH:
			# Error when the task sys.argv[3] is not found in sys.argv[2]
			sys.exit(tid)
		return

	# Always 4 parameters - other parameters are ignored
	# Parameter 2 is position, find group
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break

	# Verify parameters
	if not 'group' in locals():
		sys.exit('Invalid parameters.')
	if not is_this_task_a_group(sys.argv[3]):
		sys.exit('%s is not a group.'%sys.argv[3])
	# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
	if is_this_task_a_group(tid):
		tree_path = find_group_in_tree(sys.argv[3])
		parent_path = tree_path.split(sys.argv[3])[0]
		if tid in parent_path:
			print tree_path
			sys.exit('%s is a parent group for %s'%(tid,sys.argv[3]))
	# Verify that group is not move on itself
	if tid == sys.argv[3]:
		sys.exit('Moving %s group on itself.'%tid)
	# Verify that source group is not destination group
	if group == sys.argv[3]:
		sys.exit('Source and destination groups are identical %s.'%group)
	move_task_to_a_group(group,tid,sys.argv[3])

## copy task to a group. option -E copy description to path, first line in description is filename
#  @ingroup EDI_CLI
def copy_task():
	# Verify parameters
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')
	# option
	if sys.argv[2] == '-E':
		# Verify parameters
		if len(sys.argv) < 5:
			sys.exit('Too little parameters.')
		option      = '-E'
		sys.argv[2] = sys.argv[3]
		tid         = sys.argv[3]
	else:
		option      = ''
		tid         = sys.argv[2]

	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)

	if option == '-E':
		# Export task to a file
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		if not os.path.exists(sys.argv[4]):
			sys.exit('%s is unreachable.'%sys.argv[4])

		# Verify that task tid is in database
		tasks = os.listdir(edi_core.data_location_tasks)
		if not tid in tasks:
			sys.exit('%s not found.'%tid)

		r = export_task_to_a_file(tid,sys.argv[4])
		print 'Exported task to %s'%r
	else:
		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		# Verify that task tid is not root
		if tid == 'root':
			sys.exit('root is invalid task')
		# Verify that task tid is in database
		tasks = os.listdir(edi_core.data_location_tasks)
		if not tid in tasks:
			sys.exit('%s not found.'%tid)

		if not is_this_task_a_group(sys.argv[3]):
			sys.exit('%s is not a group.'%sys.argv[3])
		if tid == sys.argv[3]:
			sys.exit('Source and destination are identical.')
		# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
		if is_this_task_a_group(tid):
			tree_path = find_group_in_tree(sys.argv[3])
			parent_path = tree_path.split(sys.argv[3])[0]
			if tid in parent_path:
				print tree_path
				sys.exit('%s is a parent group for %s'%(tid,sys.argv[3]))
		print copy_task_to_a_group(tid,sys.argv[3])

## add a reference in group
#  @ingroup EDI_CLI
def link_task():
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	# Verify parameters
	if not is_this_task_a_group(sys.argv[3]):
		sys.exit('%s is not a group.'%sys.argv[3])
	if sys.argv[3] == find_group_containing_task(sys.argv[2]):
		sys.exit('Task %s is already in group %s.'%(sys.argv[2],sys.argv[3]))
	add_task_reference_to_a_group(sys.argv[2],sys.argv[3])

## print task filesystem path
#  @ingroup EDI_CLI
def get_task_path():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	print generate_task_path(sys.argv[2])

## print tree path
#  @ingroup EDI_CLI
def tree():
	print edi_core.data_location_tree

	DATABASE_NAME = 0
	DATABASE_PATH = 1
	print
	print 'trees'
	for d in edi_core.databases:
		print '%s - %s/tree' % (d[DATABASE_NAME], d[DATABASE_PATH])

## enable/disable (set) status filter
#  @ingroup EDI_CLI
def set_status_filter():
	if len(sys.argv)<3:
		print edi_core.status_filters_d
	else:
		if len(sys.argv)<4:
			sys.exit('Too little parameters.')
		status_name = sys.argv[2]
		state       = sys.argv[3]

		# verify parameters
		task_status = [i.strip().lower() for i in edi_core.TASK_STATUS]
		if not status_name.lower() in task_status:
			sys.exit('%s is invalid status_filter. Possible status filter are %s.'%(status_name,','.join(task_status)))
		if not state in edi_core.STATUS_FILTER_STATES:
			sys.exit('%s is invalid state. Possible states are %s.'%(state,','.join(edi_core.STATUS_FILTER_STATES)))

#:define load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
#:end
		config.set('filters',status_name,state)

#:define save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()
#:end

## set path for database
#  @ingroup EDI_CLI
def data():
	if len(sys.argv)<3:
		print 'Selected data_location'
		print edi_core.data_location
		DATABASE_NAME = 0
		DATABASE_PATH = 1
		print
		print 'Available databases'
		for d in edi_core.databases:
			print '%s - %s' % (d[DATABASE_NAME], d[DATABASE_PATH])
	else:
		if len(sys.argv)<4:
			sys.exit('Too little parameters.')
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		if sys.argv[2] == '-d':
			name           = sys.argv[3]
			try:
				path           = config.get('data',name)
			except:
				sys.exit('%s is invalid database name.'%name)
			if name == 'location':
				sys.exit('%s is invalid database name.'%name)

			# remove database from selected configuration and check that at least one database is selected
			selected       = config.get('locations','selected')
			selected_l     = selected.split(',')
			new_selected_l = []
			for i in selected_l:
				if not name in i:
					new_selected_l.append(i)
			if not new_selected_l:
				sys.exit('Select more databases before deleting %s'%name)
			new_selected   = ','.join(new_selected_l)
			config.set('locations','selected',new_selected)

			# delete database folder from file system
			# delete database from config file

			# delete database folder from file system
			if os.path.exists(path):
				shutil.rmtree(path)
			# delete database from config file - data, selected and default_add_in
			config.remove_option('data',name)

			default        = config.get('locations','default_add_in')
			if name == default:
				default = new_selected_l[0]
			config.set('locations','default_add_in',default)

			#save_ini_file
			f              = open(os.path.expanduser('~/.easydoneit.ini'),'w')
			config.write(f)
			f.close()
			#end

			print 'Deleted database %s - %s' % (name,path)
			print '\nSelected databases'
			print new_selected
			print '\nDefault for new tasks'
			print default
			return

		name = sys.argv[2]
		if name == 'location':
			sys.exit('%s is invalid database name.'%name)
		path = os.path.expanduser(sys.argv[3])

		config.set('data',name,path)
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()
		edi_core.data_location = path
		init()

## generate html for tasks
#  @ingroup EDI_CLI
def html_cli():
	# generate html header and content
	edi_core.list_option = 'html'

	html_header = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <title>Tasks</title>
    <style type="text/css">
      .subject {text-align: left}
      .plannedStartDateTime {text-align: right}
      .priority {text-align: right}
      .inactive {color: #5E5E5E}
      .late {color: #A020F0}
      .active {color: #000000}
      .duesoon {color: #FF8000}
      .overdue {color: #FF0000}
      .completed {color: #037700}

      body {
          color: #333;
          background-color: white;
          font: 11px verdana, arial, helvetica, sans-serif;
      }

      /* Styles for the title and table caption */
      h1, caption {
          text-align: center;
          font-size: 18px;
          font-weight: 900;
          color: #778;
      }

      /* Styles for the whole table */
      #table {
          border-collapse: collapse;
          border: 2px solid #ebedff;
          margin: 10px;
          padding: 0;
      }

      /* Styles for the header row */
      .header {
          font: bold 12px/14px verdana, arial, helvetica, sans-serif;
          color: #07a;
          background-color: #ebedff;
      }

      /* Mark the column that is sorted on */
      #sorted {
          text-decoration: underline;
      }

      /* Styles for a specific column */
      .subject {
          font-weight: bold;
      }

      /* Styles for regular table cells */
      td {
          padding: 5px;
          border: 2px solid #ebedff;
      }

      /* Styles for table header cells */
      th {
          padding: 5px;
          border: 2px solid #ebedff;
      }

    </style>
  </head>
  <body>
  <h1>Tasks</h1>
    <table border="1" id="table">
      <thead>
        <tr class="header">
          <th class="subject" scope="col">Subject</th>
          <th class="description" scope="col">Description</th>
        </tr>
      </thead>
      <tbody>'''

	html_footer = '''      </tbody>
    </table>
  </body>
</html>'''

      	print html_header
	ls_generic()
	print html_footer

## list selected databases or set selected databases
#  @ingroup EDI_CLI
def selected_cli():
	if len(sys.argv)>3:
		sys.exit('Too many parameters.')
	if len(sys.argv)<3:
		print 'Selected databases'
		print ','.join(edi_core.selected)
		print
		z = zip(edi_core.selected, edi_core.selected_path)
		for d,p in z:
			print '%s - %s' % (d,p)
	if len(sys.argv)==3:
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		# Verify parameter
		selected = sys.argv[2].split(',')
		if 'location' in selected:
			sys.exit('location is invalid database name.')
		for d in selected:
			if not d in dict(edi_core.databases).keys():
				sys.exit('%s is invalid database name.'%d)
		if not edi_core.default_add_in in selected:
			# default becomes first selected database
			print 'Default database %s is not selected'%edi_core.default_add_in
			print '%s is now default'%sys.argv[2].split(',')[0]
			config.set('locations','default_add_in',sys.argv[2].split(',')[0])
		config.set('locations','selected',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## set default database
#  @ingroup EDI_CLI
def default_cli():
	if len(sys.argv)>3:
		sys.exit('Too many parameters.')
	if len(sys.argv)<3:
		print 'Default for new tasks'
		print edi_core.default_add_in
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		print z[edi_core.default_add_in]
	if len(sys.argv)==3:
		# Verify parameter
		if not sys.argv[2] in edi_core.selected:
			sys.exit('%s is not selected'%sys.argv[2])
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('locations','default_add_in',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()


## copy task or group to database/group
#  @ingroup EDI_CLI
def cpb_cli():
	if len(sys.argv) < 5:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify parameters
	if not sys.argv[3] in edi_core.selected:
		sys.exit('%s database is not selected.'%sys.argv[3])
	# Verify that task tid is not root
	if sys.argv[2] == 'root':
		sys.exit('root is invalid task')
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	z                    = dict(zip(edi_core.selected, edi_core.selected_path))
	data_location        = os.path.expanduser(z[sys.argv[3]])
	data_location_groups = '%s/groups'%data_location
	if not os.path.exists('%s/%s'%(data_location_groups,sys.argv[4])):
		sys.exit('Missing destination group %s'%sys.argv[4])
	print copy_task_to_database(sys.argv[2],sys.argv[3],sys.argv[4])

## move task or group to database
#  @ingroup EDI_CLI
# 2 group<br>
# 3 task|group<br>
# 4 location<br>
# 5 group
def mvb_cli():
	if len(sys.argv) < 5:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2]       = tid
		database          = sys.argv[3]
		destination_group = sys.argv[4]
	else:
		if len(sys.argv) < 6:
			sys.exit('Too little parameters.')
		group             = sys.argv[2]
		tid               = sys.argv[3]
		database          = sys.argv[4]
		destination_group = sys.argv[5]

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify parameters
	if not database in edi_core.selected:
		sys.exit('%s database is not selected.'%database)
	# Verify that task tid is not root
	if tid == 'root':
		sys.exit('root is invalid task')
	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not tid in tasks:
		sys.exit('%s not found.'%tid)
	z                    = dict(zip(edi_core.selected, edi_core.selected_path))
	data_location        = os.path.expanduser(z[database])
	data_location_groups = '%s/groups'%data_location
	if not os.path.exists('%s/%s'%(data_location_groups,destination_group)):
		sys.exit('Missing destination group %s'%destination_group)
	print move_task_to_a_group_to_database(group,tid,database,destination_group)

## set or show foreground color
#  @ingroup EDI_CLI
def fc_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	if len(sys.argv)<4:
		color = get_forground_color(sys.argv[2])
		print '%d,%d,%d,%d' % (color[0],color[1],color[2],color[3])
	if len(sys.argv)==4:
		set_forground_color(sys.argv[2],sys.argv[3])

## set or show background color
#  @ingroup EDI_CLI
def bc_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	if len(sys.argv)<4:
		color = get_background_color(sys.argv[2])
		print '%d,%d,%d,%d' % (color[0],color[1],color[2],color[3])
	if len(sys.argv)==4:
		set_background_color(sys.argv[2],sys.argv[3])

## Create database folder and set path in .easydoneit.ini
#  @ingroup EDI_CLI
def createDatabase_cli():
	if len(sys.argv) == 4:
		name = sys.argv[2]
		path = os.path.expanduser(sys.argv[3])
		if name == 'location':
			sys.exit('%s is invalid database name.'%name)
		if (not os.path.exists(os.path.dirname(path))) and (os.path.dirname(path)):
			# os.path.dirname(path) -- to be able to create a database in current directory
			sys.exit('%s is unreachable.'%os.path.dirname(path))
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('data',name,path)
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()
		edi_core.data_location = path
		init()
	else:
		sys.exit('Too little or too many parameters. This command takes 2 parameters: databasename path_to_new_database.')

## choose or show where to add new tasks
#  @ingroup EDI_CLI
def topbot_cli():
	if len(sys.argv)<3:
		print 'Add new tasks'
		print '%s of group' % edi_core.add_top_or_bottom
	else:
		if (sys.argv[2]!='bottom') and (sys.argv[2] != 'top'):
			sys.exit('%s is invalid parameter. Possible values are "top" or "bottom".'%sys.argv[2])
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('locations','add_top_or_bottom',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## print group in md format
#  @ingroup EDI_CLI
def in_cli():
	edi_core.list_option = 'md'

	option = ''
	if len(sys.argv) > 2:
		if sys.argv[2] == '-A':
			# option to create agenda is set
			option = 'create agenda'
			del sys.argv[2]

	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if len(sys.argv) == 2:
		# no parameter - just command
		# select current group when in tree
		if status == 'in tree':
			#get_current_group_in_tree
			if cwd.split('/')[-1] == 'tree':
				group = 'root'
			else:
				group = cwd.split('/')[-1]
			#end

			task_attributes = list_group(group)
			if group == 'root':
				# for root, first task is the title in the md document
				task_attributes[0]['head'] = 'head group'
			if option == 'create agenda':
				# Generate agenda
				for t in task_attributes[1:]:
					if t['head'] != 'empty line':
						edi_core.agenda.append('%3d - %s %s'%(t['position'],t['group'],t['title']))
			print_list(task_attributes)
			return
		else:
			# default group
			group = 'root'
		sys.argv.append(group)
		# change status because there is no position parameter, no need to search for tid at given position
		status = ''

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	if not is_this_task_a_group(sys.argv[2]):
		sys.exit('%s is not a group.'%sys.argv[2])

	task_attributes = list_group(sys.argv[2])
	if sys.argv[2] == 'root':
		# for root, first task is the title in the md document
		task_attributes[0]['head'] = 'head group'
	if option == 'create agenda':
		# Generate agenda
		for t in task_attributes[1:]:
			if t['head'] != 'empty line':
				edi_core.agenda.append('%3d - %s %s'%(t['position'],t['group'],t['title']))
	print_list(task_attributes)

## print group in reStructuredText format
#  @ingroup EDI_CLI
def re_cli():
	edi_core.list_option = 'rst'

	option = ''
	if len(sys.argv) > 2:
		if sys.argv[2] == '-A':
			# option to create agenda is set
			option = 'create agenda'
			del sys.argv[2]

	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	if len(sys.argv) == 2:
		# no parameter - just command
		# select current group when in tree
		if status == 'in tree':
			#get_current_group_in_tree
			if cwd.split('/')[-1] == 'tree':
				group = 'root'
			else:
				group = cwd.split('/')[-1]
			#end

			task_attributes = list_group(group)
			if group == 'root':
				# for root, first task is the title in the rst document
				task_attributes[0]['head'] = 'head group'
			if option == 'create agenda':
				# Generate agenda
				for t in task_attributes[1:]:
					if t['head'] != 'empty line':
						# keep only title
						edi_core.agenda.append('#. %s'%t['title'])
			print_list(task_attributes)
			return
		else:
			# default group
			group = 'root'
		sys.argv.append(group)
		# change status because there is no position parameter, no need to search for tid at given position
		status = ''

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	if not is_this_task_a_group(sys.argv[2]):
		sys.exit('%s is not a group.'%sys.argv[2])

	task_attributes = list_group(sys.argv[2])
	if sys.argv[2] == 'root':
		# for root, first task is the title in the rst document
		task_attributes[0]['head'] = 'head group'
	if option == 'create agenda':
		# Generate agenda
		for t in task_attributes[1:]:
			if t['head'] != 'empty line':
				# keep only title
				edi_core.agenda.append('#. %s'%t['title'])
	print_list(task_attributes)

## show trees
#  @ingroup EDI_CLI
# print all trees: group tids and titles
def show_trees_cli():

#:loop_on_selected_databases
		z = zip(edi_core.selected, edi_core.selected_path)
		for d,path in z:
			print '%s - %s' % (d,path)
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location)
			print ''.join(show_tree())

## zip database
#  @ingroup EDI_CLI
# The path parameter is optional
# When 2 parameters are given, run data function instead.
def zip_cli():

	if len(sys.argv) < 3:
		data()
		return
	if len(sys.argv) == 3:
		# path is current directory
		zip_path = '.'
	else:
		zip_path = sys.argv[3]
	database_name = sys.argv[2]

	# Verify parameters
	if not database_name in edi_core.selected:
		sys.exit('%s database is not selected.'%database_name)
	if not os.path.exists(zip_path):
		sys.exit('%s is unreachable.'%zip_path)

	# get database system path
	z = dict(zip(edi_core.selected, edi_core.selected_path))

	# Verify parameters
	if not os.path.exists(z[database_name]):
		sys.exit('%s is unreachable.'%z[database_name])

	print 'zipped:      %s' % database_name
	print 'system path: %s' % z[database_name]
	print 'target:      %s/%s.tar.bz2' % (zip_path, database_name)
	print
	#print    ('tar -c %s | bzip2 -9 > %s/%s.tar.bz2'%(z[database_name], zip_path, database_name))
	os.system('tar -cj %s > %s/%s.tar.bz2'%(z[database_name], zip_path, database_name))

## list autolink groups or set autolink groups
#  @ingroup EDI_CLI
def autolink_cli():
	if len(sys.argv)<3:
		print 'Autolink groups'
		if not edi_core.autolink:
			print 'Empty'
		else:
			print ','.join(edi_core.autolink)
			print
			print '\n'.join(edi_core.autolink)
	if len(sys.argv)==3:
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('locations','autolink',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## convert empty group to task
#  @ingroup EDI_CLI
def cv_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is not root
	if sys.argv[2] == 'root':
		sys.exit('root is invalid group')
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	if not is_this_task_a_group(sys.argv[2]):
		sys.exit('%s is not a group.'%sys.argv[2])
	print '\n'.join(convert_group_to_task(sys.argv[2]))

## display user name or set user name
#  @ingroup EDI_CLI
def user_cli():
	if len(sys.argv)<3:
		print 'User name: %s <%s>'%(edi_core.user,edi_core.email)
	if len(sys.argv)>3:
		sys.exit('Too many parameters.')
	if len(sys.argv)==3:
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('settings','username',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## display user email or set user email
#  @ingroup EDI_CLI
def email_cli():
	if len(sys.argv)<3:
		print 'User name: %s <%s>'%(edi_core.user,edi_core.email)
	if len(sys.argv)>3:
		sys.exit('Too many parameters.')
	if len(sys.argv)==3:
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('settings','useremail',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## show statistics
#  @ingroup EDI_CLI
def stats_cli():
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	# Decide what to execute
	if len(sys.argv) == 2:
		tid = 'root'
		if status:
			# in tree, set tid to cwd
			tid = cwd.split('/')[-1]
			if tid == 'tree':
				tid = 'root'
			exe = 'stats in tree'
		else:
			exe = 'stats root'
	else:
		tid = sys.argv[2]

#:find_task_in_selected_databases_and_setup_data_location
		if tid == 'root':
			#set_default_database
			z = dict(zip(edi_core.selected, edi_core.selected_path))
			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
		elif tid != 'tree':
			for path in edi_core.selected_path:
				edi_core.data_location        = os.path.expanduser(path)
				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

				if not os.path.exists(edi_core.data_location):
					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
				tasks = os.listdir(edi_core.data_location_tasks)
				if tid in tasks:
					break
		exe = 'stats parameter'

	if exe == 'stats root':
#:loop_on_selected_databases
		z = zip(edi_core.selected, edi_core.selected_path)
		for d,path in z:
			print '%s - %s' % (d,path)
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location)
			print '\n'.join(statistics('for database'))
	else:
		if not is_this_task_a_group(tid):
			sys.exit('Group %s not found.'%tid)

		print '\n'.join(statistics(tid))

## add many tasks or many groups
#  @ingroup EDI_CLI
def many_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')

#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

	options                = ''
	group_parameter_status = 'group is a command line parameter'
	if len(sys.argv) < 4:
		# Parameters are: command filename
		# select current group when in tree
		if status == 'in tree':
			#get_current_group_in_tree
			if cwd.split('/')[-1] == 'tree':
				group = 'root'
			else:
				group = cwd.split('/')[-1]
			#end
		else:
			# default group
			group = 'root'
		group_parameter_status = 'edi selected group'

		text_file = sys.argv[2]
	else:
		if ((sys.argv[2] == '-1') or (sys.argv[2] == '-g')) and len(sys.argv) == 4:
			options   = sys.argv[2]
			text_file = sys.argv[3]
			# select current group when in tree
			if status == 'in tree':
				#get_current_group_in_tree
				if cwd.split('/')[-1] == 'tree':
					group = 'root'
				else:
					group = cwd.split('/')[-1]
				#end
			else:
				# default group
				group = 'root'
			group_parameter_status = 'edi selected group'
		if ((sys.argv[2] == '-1') or (sys.argv[2] == '-g')) and len(sys.argv) == 5:
			options   = sys.argv[2]
			group     = sys.argv[3]
			text_file = sys.argv[4]
		if ((sys.argv[2] != '-1') and (sys.argv[2] != '-g')):
			group     = sys.argv[2]
			text_file = sys.argv[3]
	if not options:
		exe = 'add'
	else:
		if options == '-1':
			# option -1 adds one task per line in text_file
			exe = 'add one task per line'
		elif options == '-g':
			# option -F stores text_file filename in first line of description
			exe = 'add groups from text file'

	if (group == 'root') and (not status):
		# set default database when group is root and cwd not in tree
#:set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	if (group != 'root') and ((not status) or (group_parameter_status == 'group is a command line parameter')):
#:find_group_in_selected_databases_and_setup_data_location
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			groups = os.listdir(edi_core.data_location_groups)
			if group in groups:
				break

	if not is_this_task_a_group(group):
		sys.exit('%s is not a group.'%group)

	if not os.path.exists(text_file):
		sys.exit('%s unreachable file.'%text_file)

	if exe == 'add':
		print add_many_tasks(group,text_file)
	if exe == 'add one task per line':
		print add_many_one_line_tasks(group,text_file)
	if exe == 'add groups from text file':
		print add_many_groups_from_text(group,text_file)

## demo to show how to use Easydoneit CLI
#  @ingroup EDI_CLI
def demo_cli():
	print '# Easydoneit CLI - Demo'
	# print (), to print without a newline
	print ('#'),
#:edi_version
	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
	v = f.readline()
	f.close()
	print 'Version %s'%v

	print '''
# Run the commands below in a terminal

# create the demo database
edi createDatabase easydoneit_cli_demo ~/easydoneit_cli_demo

# show selected databases - SAVE THIS STRING
edi select

# show default database - SAVE THIS STRING
edi default

# select demo database
edi select easydoneit_cli_demo

# demo database is default
edi default easydoneit_cli_demo

# the configuration file is in your home, change text editor if you dont use VI
cat ~/.easydoneit.ini

# create a task in default database, type your task in the text editor
edi cr

# list tasks
edi ls

# add task directly from command line
edi add -t demo_task_1
edi add -t 'demo task 2 - string with spaces'
edi ls

# tasks can be added on the top of the list
edi topbot top

# add task from file
echo 'demo task 3' > ~/demo_3.txt
edi add ~/demo_3.txt
rm ~/demo_3.txt
edi ls

# choose to add tasks at the bottom
edi topbot bottom

# it is simpler to use Easydoneit CLI in the tree
cd ~/easydoneit_cli_demo/tree
edi ls

# create a group using position
edi mkdir 0

# background color
edi bc 0 230,230,230,255

# change order, moves task at position 0 to position 2
edi order 0 2

# change state to done, pending and inactive
edi set 0 1
edi set 1 3
edi set 2 4
edi ls

# display the complete tree of groups
edi st

# filter out done tasks
edi stfi done disable
edi ls

# search
edi search demo

# delete task
edi rm 1

# display system path for a task
edi path 2

# generate html
edi html

# generate reStructuredText (rst)
edi re

# zip
edi zip easydoneit_cli_demo ~/

# delete database, RESELECT YOUR DATABASES WITH edi select BEFORE RUNNING THE COMMANDS BELOW
cd -
edi data -d easydoneit_cli_demo
edi data

# remove database zip
rm ~/easydoneit_cli_demo.tar.bz2

# end
	'''

## set list of group for edi ls -L, -La and -Lx options
#  @ingroup EDI_CLI
def list_cli():
	if len(sys.argv)<3:
		print 'list of groups'
		if not edi_core.list_of_groups:
			print 'Empty'
		else:
			print ','.join(edi_core.list_of_groups)
			print
			print '\n'.join(edi_core.list_of_groups)
	if len(sys.argv)==3:
#:load_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'))
		# load config from user home
		config = ConfigParser.ConfigParser()
		config.readfp(f)
		f.close()
		config.set('locations','list',sys.argv[2])
#:save_ini_file
		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
		config.write(f)
		f.close()

## copy database sys.argv[2] to database sys.argv[3]
#  @ingroup EDI_CLI
def merge_cli():
	if len(sys.argv) < 4:
		sys.exit('Too little parameters.')

	# set source path (argv 2)
	path             = ''
	if os.path.exists(sys.argv[2]):
		path = sys.argv[2]
	if not path:
		# argv 2 could be a database name
		dbs  = dict(edi_core.databases)
		if sys.argv[2] in dbs.keys():
			path = dbs[sys.argv[2]]
	if not path:
		sys.exit('Source database %s not found.'%sys.argv[2])

	# check source database structure
	directories      = ['tasks', 'groups', 'tree']

	status = 'source database structure ok'
	for d in directories:
		directory = '%s/%s'%(path, d)
		if not os.path.exists(directory):
			print 'Missing %s'%directory
			status = 'missing directories in source database'
	if status == 'missing directories in source database':
		sys.exit('Invalid source database %s'%path)

	# check destination database
	if not sys.argv[3] in edi_core.selected:
		sys.exit('%s database not selected.'%sys.argv[3])

	s                = dict(zip(edi_core.selected, edi_core.selected_path))
	destination_path = s[sys.argv[3]]

	# copy database
	for d in directories:
		directory  = '%s/%s'%(path, d)
		ddirectory = '%s/%s'%(destination_path, d)
		os.system('cp -R %s/* %s'%(directory,ddirectory))


## copy media sys.argv[3] to task sys.argv[2]
#  @ingroup EDI_CLI
def media_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	if len(sys.argv)<4:
		print '\n'.join(get_media(sys.argv[2]))
	if len(sys.argv)==4:
		if not os.path.exists(sys.argv[3]):
			sys.exit('%s not found.'%sys.argv[3])
		print set_media(sys.argv[2],sys.argv[3])


## copy attachments sys.argv[3] to task sys.argv[2]
#  @ingroup EDI_CLI
def at_cli():
	if len(sys.argv) < 3:
		sys.exit('Too little parameters.')
	# Figure out if the command is run in the tree
#:figure_out_if_in_tree
	status        = ''
	cwd           = os.path.realpath(os.getcwd())
	#loop_on_selected_databases
	z             = zip(edi_core.selected, edi_core.selected_path)
	for d,path in z:
		edi_core.data_location        = os.path.expanduser(path)
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

		# check path from left
		real_tree_path = os.path.realpath(edi_core.data_location_tree)
		if real_tree_path == cwd[:len(real_tree_path)]:
			status = 'in tree'
			p_l    = edi_core.data_location_tree.split('/')[-2:]
			break

#:find_task_sysargv2_in_selected_databases
	# the goal for this code is to reset status when a tid is an existing task
	# when parameter is taskid, it doesnt matter if cwd is in tree
	# find task in selected databases
	for path in edi_core.selected_path:
		data_location        = os.path.expanduser(path)
		data_location_tasks  = '%s/tasks'%data_location

		if not os.path.exists(data_location):
			sys.exit('%s is unreachable.'%path)
		tasks = os.listdir(data_location_tasks)
		if sys.argv[2] in tasks:
			# found task, setup database below
			status = ''
			break

	if status == 'in tree':
#:get_current_group_in_tree
		if cwd.split('/')[-1] == 'tree':
			group = 'root'
		else:
			group = cwd.split('/')[-1]
#:get_position_from_argv2
		try:
			position    = int(sys.argv[2])
		except:
			sys.exit('%s is invalid position'%sys.argv[2])
#:find_task_at_position
		if position < 0:
			sys.exit('Position %d is invalid.'%position)
		group_tasks = os.listdir(generate_group_path(group))
		order_id    = baseconvert(position)
		tid         = ''
		for t in group_tasks:
			# find exact match
			if order_id == t[:ORDER_ID_LENGTH]:
				tid = t[ORDER_ID_LENGTH:]
		if not tid:
			sys.exit('Position %d does not exist.'%position)
		sys.argv[2] = tid

	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
#:tab1_find_task_in_selected_databases_and_setup_data_location
	if sys.argv[2] == 'root':
		#set_default_database
		z = dict(zip(edi_core.selected, edi_core.selected_path))
		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
		if not os.path.exists(edi_core.data_location):
			sys.exit('%s is unreachable.'%edi_core.data_location)
	else:
		for path in edi_core.selected_path:
			edi_core.data_location        = os.path.expanduser(path)
			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location

			if not os.path.exists(edi_core.data_location):
				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
			tasks = os.listdir(edi_core.data_location_tasks)
			if sys.argv[2] in tasks:
				break
	# Verify that task tid is in database
	tasks = os.listdir(edi_core.data_location_tasks)
	if not sys.argv[2] in tasks:
		sys.exit('%s not found.'%sys.argv[2])
	if len(sys.argv)<4:
		print '\n'.join(get_attachments(sys.argv[2]))
	if len(sys.argv)>3:
		for fn in sys.argv[3:]:
			if not os.path.exists(fn):
				sys.exit('%s not found.'%fn)
		print '\n'.join(set_attachments(sys.argv[2],sys.argv[3:]))


## CLI command functions
FUNCTIONS    = [help,version,create_task_cli,lsid,add_task_cli,cat,mkdir,show_group_for_task_cli,rm,vi,change_order,set,reset,search,move_task,copy_task,link_task,get_task_path,tree,ls,set_status_filter,data,html_cli,selected_cli,default_cli,cpb_cli,mvb_cli,fc_cli,bc_cli,createDatabase_cli,topbot_cli,in_cli,re_cli,show_trees_cli,zip_cli,autolink_cli,cv_cli,user_cli,email_cli,stats_cli,many_cli,demo_cli,list_cli,merge_cli,media_cli,at_cli]

COMMAND_MAP = dict(zip(COMMANDS,FUNCTIONS))


if __name__ == '__main__':
#:print_command_map
#:end
	start() #pragma: no cover

	if len(sys.argv)> 1: #pragma: no cover
		# remove whitespaces from parameters. ^M can come for scripts
		for i,a in enumerate(sys.argv[1:]): #pragma: no cover
			sys.argv[i+1] = a.strip()  #pragma: no cover
#:not profiler
		COMMAND_MAP.get(sys.argv[1],Nothing)() #pragma: no cover
#:else
#:end
	else:
		help() #pragma: no cover
#:profiler
#:end
